﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using GrafosWindows.Model;
using GrafosWindows.Persistencia;

namespace GrafosWindows
{
    public partial class Aplicacao : Form
    {
        #region Atributos
        private Grafo _grafo;
        internal Grafo Grafo
        {
            get { return _grafo; }
            set { _grafo = value; }
        }

        private Graphics _graphics;
        public Graphics Graphics
        {
            get { return _graphics; }
            private set { _graphics = value; }
        }

        private Bitmap backBuffer;
        #endregion

        public Aplicacao()
        {
            InitializeComponent();

            backBuffer = new Bitmap(panelGrafo.Width, panelGrafo.Height);
            Graphics = Graphics.FromImage(backBuffer);
            panelGrafo.Paint += panelGrafo_Paint;
        }

        void panelGrafo_Paint(object sender, PaintEventArgs e)
        {
            e.Graphics.DrawImageUnscaled(backBuffer, 0, 0);
        }

        #region Código dos Butões
        private void buttonAbrir_Click(object sender, EventArgs e)
        {
            textBoxCaminho.Text = IOUtils.OpenFileDialogShow(this);
        }

        private void buttonLimpar_Click(object sender, EventArgs e)
        {
            textBoxCaminho.Text = "";
        }

        private void buttonCarregar_Click(object sender, EventArgs e)
        {
            string[] arquivo = IOUtils.ReadTxtFile(textBoxCaminho.Text);
            Grafo = new Grafo(arquivo);

            PintarGrafoPanel();

            liberarButoes(true);
            carregarComboBox();
        }

        private void PintarGrafoPanel()
        {
            panelGrafo.Controls.Clear();
            Graphics.Clear(Color.White);
            panelGrafo.Invalidate();
            pintarGrafo();
        }

        private void buttonCaminho_Click(object sender, EventArgs e)
        {
            PintarGrafoPanel();

            List<Vertice> caminho = Grafo.Caminho(Grafo.HashVertices[comboBoxV.Text], Grafo.HashVertices[comboBoxU.Text]);
            if (caminho.Count > 0)
            {
                Pen pen = new Pen(Color.Blue);
                for (int i = 0; i < caminho.Count - 1; i++)
                {
                    Graphics.DrawLine(pen, caminho[i].Posicao, caminho[i + 1].Posicao);
                }
                pen.Dispose();
            }
            else
            {
                MessageBox.Show("Não existe caminho entre os vértices " + comboBoxV.Text + " e " + comboBoxU.Text);
            }
        }

        private void buttonDjikstra_Click(object sender, EventArgs e)
        {
            PintarGrafoPanel();

            List<Vertice> caminho = Grafo.CaminhoDijkstra(Grafo.HashVertices[comboBoxV.Text], Grafo.HashVertices[comboBoxU.Text]);
            if (caminho.Count > 0)
            {
                Pen pen = new Pen(Color.Blue);
                for (int i = 0; i < caminho.Count - 1; i++)
                {
                    Graphics.DrawLine(pen, caminho[i].Posicao, caminho[i + 1].Posicao);
                }
                pen.Dispose();
            }
            else
            {
                MessageBox.Show("Não existe caminho entre os vértices " + comboBoxV.Text + " e " + comboBoxU.Text);
            }
        }

        private void buttonArvoreMinima_Click(object sender, EventArgs e)
        {
            Grafo novoGrafo = Grafo.ArvoreMinima();
            JanelaGrafo janelaGrafo = new JanelaGrafo(novoGrafo);
        }

        private void buttonArvoreDijkstra_Click(object sender, EventArgs e)
        {
            Grafo novoGrafo = Grafo.ArvoreDijkstra(Grafo.HashVertices[comboBoxV.Text]);
            JanelaGrafo janelaGrafo = new JanelaGrafo(novoGrafo);
        }

        private void liberarButoes(bool liberar)
        {
            buttonCaminho.Enabled = liberar;
            buttonDjikstra.Enabled = liberar;
        }
        #endregion

        #region Código das Funcionalidades
        private void carregarComboBox()
        {
            comboBoxU.Items.Clear();
            comboBoxV.Items.Clear();

            foreach (Vertice vertice in Grafo.ListaVertices)
            {
                comboBoxU.Items.Add(vertice);
                comboBoxV.Items.Add(vertice);
            }
        }
        #endregion

        #region Código do Panel do Grafo
        private void pintarGrafo()
        {
            //No máximo 5 nós por linha
            int qtdeLinhas = 1;
            if (Grafo.Cardinalidade > 5)
            {
                qtdeLinhas = Grafo.Cardinalidade % 5;
                qtdeLinhas++;
            }

            int xInicial = 50;
            int yInicial = 60;

            int tamanho = 15;

            SolidBrush brush = new SolidBrush(Color.DarkGreen);
            SolidBrush brushEffect = new SolidBrush(Color.Black);
            SolidBrush brushText = new SolidBrush(Color.Black);

            for (int j = 0; j < Grafo.ListaVertices.Count; j++)
            {
                //Para garantir que ficará no centro do vértice somamos com tamanho/2
                Grafo.ListaVertices[j].Posicao = new Point(xInicial + (tamanho / 2), yInicial + (tamanho / 2));

                Graphics.DrawString(Grafo.ListaVertices[j].Name, new Font("Arial", 12), brushText, (float)xInicial, (float)yInicial - tamanho);
                Graphics.FillEllipse(brushEffect, xInicial - 1, yInicial - 1, tamanho + 2, tamanho + 2);
                Graphics.FillEllipse(brush, xInicial, yInicial, tamanho, tamanho);

                xInicial += 60;
                switch ((j + 1) % 5)
                {
                    case 0: break;
                    case 1: yInicial += (20 + ((j + 1) % 5) * 5); break;
                    case 2: yInicial -= (30 + ((j + 1) % 5) * 5); break;
                    case 3: yInicial -= (10 + ((j + 1) % 5) * 5); break;
                    case 4: yInicial += (15 + ((j + 1) % 5) * 5); break;
                }

                if ((j+1) % 5 == 0)
                {
                    xInicial = 50 + ((j + 1) % 5) * 5;
                    yInicial += 80;
                }
            }

            brush.Dispose();
            brushText.Dispose();

            Pen pen = new Pen(Color.Red);

            foreach(Vertice vertice in Grafo.ListaVertices)
            {
                foreach (Aresta aresta in vertice.Arestas)
                {
                    pen = new Pen(Color.FromArgb(25 * aresta.Peso, 0, 0));
                    Graphics.DrawLine(pen, vertice.Posicao, aresta.U.Posicao);
                }
            }

            pen.Dispose();
        }
        #endregion
        
    }
}
